package models

import (
	"go/ast"
)

// FieldInfo is the field info
type FieldInfo struct {
	Name string
	Type string
	Tag  string
}

type FieldsInfo []*FieldInfo

func (f *FieldsInfo) Visit(node ast.Node) ast.Visitor {
	switch n := node.(type) {
	case *ast.Field:
		name := ""
		if n.Names != nil && len(n.Names) > 0 {
			name = n.Names[0].Name
		}
		tag := ""
		if n.Tag != nil {
			tag = n.Tag.Value
		}
		field := &FieldInfo{
			Name: name,
			Type: getType(n.Type),
			Tag:  tag,
		}
		*f = append(*f, field)
		return nil
	}
	return f
}

// StructInfo is the struct info
type StructInfo struct {
	Name        string
	Fields      FieldsInfo
	Methods     []*MethodInfo
	Annotations *Annotations
	Package     *PackageInfo
}

// ModelName return the name of the model of the DataObject
func (s *StructInfo) ModelName() string {
	nameAnno, _ := s.Annotations.Get(AnnotationName)
	if nameAnno != nil && nameAnno.Value != "" {
		return nameAnno.Value
	}
	return s.Name
}

func (s *StructInfo) GetAnnotation(name string) *Annotation {
	a, _ := s.Annotations.Get(name)
	return a
}

func (s *StructInfo) GetMethod(name string) (*MethodInfo, bool) {
	for _, method := range s.Methods {
		if method.Name == name {
			return method, true
		}
	}
	return nil, false
}

func NewStructInfo(name string, pkg *Package) *StructInfo {
	return &StructInfo{
		Name:        name,
		Fields:      make([]*FieldInfo, 0),
		Methods:     make([]*MethodInfo, 0),
		Annotations: NewAnnotations(),
		Package:     &pkg.PackageInfo,
	}
}

func (s *StructInfo) Visit(node ast.Node) ast.Visitor {
	switch node.(type) {
	case *ast.CommentGroup:
		return s.Annotations
	case *ast.FieldList:
		return &s.Fields
	}
	return s
}
